//addという変数を定義して関数を格納する
var add = function( a,b){
  if( typeof a !== 'number' || typeof b !== 'number'){
    throw{
      name:'type error',
      message:'add needs numbers'
    };

  }
  return a + b;
}

//4.3.1
var myObject = {

  value: 0,

  increment: function (inc){
    this.value += typeof inc === 'number' ? inc : 1;
  }
};

myObject.increment();
document.writeln( myObject.value );

myObject.increment(2);
document.writeln( myObject.value );


//myObejctにdoubleメソッドを追加する
myObject.double = function(){

  var that = this;

  var helper = function(){
    that.value = add(that.value, that.value);
  };

  helper();
};

myObject.double();
document.writeln( myObject.value );


//4.3.3
var Quo = function(string){

  this.status = string;
};

//get_statusというパブリックメソッドを
//Quoのすべてのインスタンスで利用可能に

Quo.prototype.get_status = function(){

  return this.status;
};

var myQuo = new Quo("confused");
document.writeln( myQuo.get_status() );

//4.3.4
var array = [3,4];
var sum = add.apply(null, array );

var statusObject = {

  status:'A-OK',
};

var status = Quo.prototype.get_status.apply(statusObject);


//4.4
var sum = function(){
  var i;
  var sum = 0;

  for ( var i = 0; i < arguments.length; i++) {
    sum += arguments[i];
    
  }

  return sum;

};


document.writeln( sum(4,8,15,16,23,42));


//4.6
//addという変数を定義して関数を格納する
/*
var add = function( a,b){
  if( typeof a !== 'number' || typeof b !== 'number'){
    throw{
      name:'type error',
      message:'add needs numbers'
    };

  }
  return a + b;
}
*/

var try_it = function (){
  try {
    add("seven");
  } catch(e) {
    document.writeln( e.name + ":" + e.message);
  }
}

try_it();

//4.7
Function.prototype.method = function(name, func){

  this.prototype[name] = func;
  return this;
  
}

Number.method('integer', function(){
                return Math[this < 0 ? 'ceil' : 'floor'](this);
              });


document.writeln( (-10/3).integer() );
document.writeln( Math.ceil(-10/3) );
document.writeln( Math.floor(-10/3) );

String.method( 'trim', function(){
                 return this.replace(/^\s+|\s+$/g ,'');
               });

document.writeln( '"' + "   neat   ".trim() + '"');

Function.prototype.method = function( name, func ){

  if( !this.prototype[name]){
    this.prototype[name] = func;
    return this;
  }
  
}

//4.8
var hanoi = function(disc, src, aux, dst){

  if( disc > 0 ){
    hanoi( disc-1, src, dst, aux);
    document.writeln("Move disc" + disc + ' from ' + src + ' to ' + dst);
    document.writeln("<br>");
    hanoi(disc-1, aux, src, dst);
  }

};

hanoi( 3, "Src", "Aux", "Dst");

var walk_the_DOM = function walk( node, func ){

  func(node);
  node = node.fistChild;
  while( node ){
    walk( node, func );
    node = node.nextSibling;
  }
};

var getElementsByAttribute = function ( att, value ){

  var results = [];

  walk_the_DOM( document.body, function(node){
                  var actual = node.nodeType === 1 && node.getAttribute(att);
                  if( typeof actual == 'string' && ( actual === value || typeof value !== 'string' )){
                    results.push(node);
                  }
                });
  return results;
};


//4.10
var myObject = function () {

  var value = 0;
  return {
    increment: function( inc ){
      value += typeof inc == "number" ? inc :1;
    },
    getValue: function(){

      return value;
    }
  };
}();


var quo = function(status){

  return {
    get_status: function(){
      return status;
    }
  }
};

var myQuo = quo("amazed");
document.writeln( myQuo.get_status());

//4.11
/*
request = prepare_the_send();
rquest_request_asynchronously( request, function(response){
                               display(response);
                               
                             });
 */
//4.12
String.method('deentityify', function(){

                var entity = {
                  quot: '"',
                  lt: '<',
                  gt: '>'
                  };

                return function(){

                  return this.replace(/&([^&;]+);/g,
                                      function(a, b){
                                        var r = entity[b];
                                        return typeof r === 'string' ? r:a;
                                      }
                                     );
                };
                
              }());

document.writeln( '&lt;&quot;&gt;'.deentityify());
  

//4.14
Function.method('curry', function() {

                 var slice = Array.prototype.slice;
                 var args = artuments;
                 var that = this;
                 return function(){
                   return that.apply( null, args.concat( slice.apply(arguments)));
                 };
               });


//4.15
var fibonacci = function (){
  var memo = [0,1];
  var fib = function(n){
    var result = memo[n];
    if( typeof result !== 'number'){
      result = fib(n-1) + fib(n-2);
      memo[n] = result;
    }
    return result;
  };
  return fib;
}();

for ( var i = 0; i <= 10 ; i++) {
  document.writeln("<br>");
  document.writeln( '//' + i + ";" + fibonacci(i) );
}

  